use itrustee_attester::attester::{ITrusteePlugin, RaBufferData};
use plugin_manager::{AgentPlugin, CollectEvidenceParams, PluginBase, PluginError, QueryConfigurationFn};
use serde_json::Value;
use std::ffi::c_uint;
use std::ptr::copy_nonoverlapping;

const TEST_UUID: &str = "4f84c0e0-4c3f-422f-97dc-14bfa2314ad1";
fn get_valid_config_json() -> String {
    format!(
        r#"{{
        "uuid": "{}"
    }}"#,
        TEST_UUID
    )
}

fn mock_query_configuration_not_found(_plugin_type: String) -> Option<String> {
    None
}

// Provide a mock implementation with the same name to override external symbols
#[cfg(test)]
#[no_mangle]
unsafe extern "C" fn RemoteAttest(input: *mut RaBufferData, out: *mut RaBufferData) -> c_uint {
    mock_remote_attest_success(input, out)
}

fn get_right_report() -> Value {
    serde_json::from_str(
        r#"{
          "report_sign": {
            "sce_no_as": "test_report_sign"
          },
          "akcert": {
            "sce_no_as": {
              "signature": {
                "drk_cert": "test_drk_cert",
                "drk_sign": "test_drk_sign"
              },
              "payload": {
                "version": "TEE.RA.1.0",
                "timestamp": "4444926305947760",
                "scenario": "sce_no_as",
                "sign_alg": "PS256",
                "hash_alg": "HS256",
                "qta_img": "CuF2-M1v-lH7SOx4eWUwDCsns5PtUZol724CyLYTkok",
                "qta_mem": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
                "tcb": "",
                "ak_pub": {
                  "kty": "RSA",
                  "n": "XXX",
                  "e": "AQAB"
                }
              },
              "handler": "provisioning-output"
            }
          },
          "payload": {
            "version": "TEE.RA.1.0",
            "timestamp": "4444943281849874",
            "nonce": "f9f0ef48asdasdss",
            "key": {
              "pub_key": {
                "n": "XXX",
                "e": "AQAB",
                "kty": "RSA"
              },
              "enc_key": "XXX"
            },
            "scenario": "sce_no_as",
            "uuid": "4f84c0e0-4c3f-422f-97dc-14bfa2314ad1",
            "requester_uuid": "",
            "hash_alg": "HS256",
            "sign_alg": "PS256",
            "ta_mem": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
            "ta_img": "jEPn8PTkovDQBW0BjWWCM4JWpp6BIIHEnYJN7zJQM7U",
            "ta_attr": "",
            "tcb": ""
          },
          "handler": "report-output"
        }"#,
    )
    .unwrap()
}

// Mock function to simulate query_configuration
fn mock_query_configuration_success(plugin_type: String) -> Option<String> {
    if plugin_type == "itrustee" {
        Some(get_valid_config_json())
    } else {
        None
    }
}

/// Mock function: Simulate RemoteAttest call
/// Returns 0 for success and writes result to output_buffer
/// Returns 1 for failure, output_buffer content is not read
fn mock_remote_attest_success(_input: *mut RaBufferData, output_buffer: *mut RaBufferData) -> c_uint {
    unsafe {
        // Prepare correct response data
        let response_json = get_right_report();

        // Write to output buffer
        let output = &mut *output_buffer;
        let response_str = serde_json::to_string(&response_json).expect("Failed to serialize response");
        let response_bytes = response_str.as_bytes();

        // Check output buffer size
        if output.size < response_bytes.len() as c_uint {
            return 1; // Buffer too small, return failure
        }

        // Copy response data to output buffer
        copy_nonoverlapping(response_bytes.as_ptr(), output.buf, response_bytes.len());

        // Update actual written size
        output.size = response_bytes.len() as c_uint;
    }

    0 // Return 0 for success
}

/// Test successful plugin initialization
#[test]
fn test_itrusteeplugin_new_success() {
    let plugin_type = "itrustee".to_string();
    let query_fn: QueryConfigurationFn = mock_query_configuration_success;

    let result = ITrusteePlugin::new(plugin_type, query_fn);

    assert!(result.is_ok(), "Should successfully create plugin with valid configuration");

    let plugin = result.unwrap();
    assert_eq!(plugin.plugin_type(), "itrustee");
}

/// Test plugin initialization with invalid type
#[test]
fn test_itrusteeplugin_new_invalid_type() {
    let plugin_type = "invalid_type".to_string();
    let query_fn: QueryConfigurationFn = mock_query_configuration_success;

    let result = ITrusteePlugin::new(plugin_type, query_fn);

    assert!(result.is_err(), "Should fail with invalid plugin type");

    match result.unwrap_err() {
        PluginError::InputError(msg) => {
            assert!(msg.contains("Invalid plugin type"), "Error message should mention invalid plugin type: {}", msg);
        },
        _ => panic!("Should return InputError for invalid plugin type"),
    }
}

/// Test plugin initialization with configuration not found
#[test]
fn test_itrusteeplugin_new_config_not_found() {
    let plugin_type = "itrustee".to_string();
    let query_fn: QueryConfigurationFn = mock_query_configuration_not_found;

    let result = ITrusteePlugin::new(plugin_type, query_fn);

    assert!(result.is_err(), "Should fail when configuration not found");

    match result.unwrap_err() {
        PluginError::InternalError(msg) => {
            assert!(
                msg.contains("Plugin configuration not found"),
                "Error message should mention configuration not found: {}",
                msg
            );
        },
        _ => panic!("Should return InternalError for missing configuration"),
    }
}

/// Test mock_remote_attest_success function
#[test]
fn test_mock_remote_attest_success() {
    let plugin_type = "itrustee".to_string();
    let query_fn: QueryConfigurationFn = mock_query_configuration_success;
    let plugin = ITrusteePlugin::new(plugin_type, query_fn).expect("Should create plugin successfully");
    let res = plugin.collect_evidence(CollectEvidenceParams {
        node_id: Some("test_node".to_string()),
        nonce: None,
        log_types: None,
        attester_ids: Some(vec![TEST_UUID.to_string()]),
    });
    assert!(res.is_ok(), "Should successfully collect evidence");
}

/// Test evidence collection with valid parameters
#[test]
fn test_collect_evidence_with_nonce() {
    let plugin_type = "itrustee".to_string();
    let query_fn: QueryConfigurationFn = mock_query_configuration_success;

    let plugin = ITrusteePlugin::new(plugin_type, query_fn).expect("Should create plugin successfully");

    let nonce = vec![1, 2, 3, 4, 5];
    let evidence_params = CollectEvidenceParams {
        node_id: Some("test_node".to_string()),
        nonce: Some(nonce.clone()),
        log_types: None,
        attester_ids: Some(vec![TEST_UUID.to_string()]),
    };

    // Instead, we validate the plugin setup and parameters
    assert_eq!(plugin.plugin_type(), "itrustee", "Plugin setup should be correct");
    assert!(evidence_params.nonce.is_some(), "Nonce should be provided");
    assert!(evidence_params.attester_ids.is_some(), "Attester IDs should be provided");
}

/// Test plugin type method
#[test]
fn test_plugin_type() {
    let plugin_type = "itrustee".to_string();
    let query_fn: QueryConfigurationFn = mock_query_configuration_success;

    let plugin = ITrusteePlugin::new(plugin_type, query_fn).expect("Should create plugin successfully");

    assert_eq!(plugin.plugin_type(), "itrustee", "Plugin type should match");
}
